/**
 * 
 */
package com.magnusart.scrumppm.gui;

import static com.magnusart.scrumppm.model.States.PROJECT_CHOOSER;
import static com.magnusart.scrumppm.model.States.PROJECT_CREATE_NEW;
import static com.magnusart.scrumppm.model.States.PROJECT_DETAILS;

import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import com.magnusart.scrumify.dao.CommonDAO;
import com.magnusart.scrumify.dao.DAOFactory;
import com.magnusart.scrumppm.model.Project;
import com.magnusart.scrumppm.model.ProjectBuilder;
import com.magnusart.scrumppm.model.States;
import com.magnusart.scrumppm.model.States.Transition;
import com.magnusart.scrumppm.presenters.CreateNewPresenter;
import com.magnusart.scrumppm.presenters.GlobalEvents;
import com.magnusart.scrumppm.presenters.MenuPresenter;
import com.magnusart.scrumppm.presenters.ProjectChooserPresenter;
/**
 * The main GUI interface class for ScrumPPM
 * @author Magnus Andersson
 *
 */
public final class ScrumPPM implements Observer
{
	private final Map<States,Composite> stateComposite;
	
	private ProjectChooser projectChooser;
	private ProjectCreateNew projectCreateNew;
	private MenuBar menuBar;

	private StackLayout stackLayout;

	private MainPlaceholder mainPlaceholder;
	
	private static final int WINDOW_WIDTH = 800;
	private static final int WINDOW_HEIGHT = 600;
	private static final String INITIAL_WINDOW_TITLE = "Scrum Personal Project Management";
	
	/**
	 * This is the parent window.
	 * @param display 
	 */
	public ScrumPPM( Shell shell ) {
		// State machine takes care of what to show, and when.
		
		// Observe the state machine
		States.observe().addObserver( this );
		
		// Make sure that the initial state is the Project chooser.
		assert( States.currentState().equals( PROJECT_CHOOSER ) );
		
		// Maps between states and view objects.
		stateComposite = new HashMap<States,Composite>();
		
		//addStatusLine();

		configureShell( shell );
		createContents( shell );
		addPresenters();
	}
	

	private void configureShell( Shell shell ) {
		shell.setText( INITIAL_WINDOW_TITLE );
		shell.setSize( WINDOW_WIDTH, WINDOW_HEIGHT );
	}
	
	/**
	 * Creates the content and adds it to the shell
	 * @param shell Parent view.
	 */
	private void createContents( Shell shell ) {		
		// This stack layout is used to switch view.
		stackLayout = new StackLayout(); 

		shell.setLayout( stackLayout ); // new GridLayout( 1, true ) );

		// Creates a menu bar
		menuBar = new MenuBar( shell );

		// Add the different views.
		projectChooser = new ProjectChooser( shell );
		projectCreateNew = new ProjectCreateNew( shell );
		mainPlaceholder = new MainPlaceholder( shell );
		
		stackLayout.topControl = projectChooser;
		
		// Map the different states to different views.
		stateComposite.put( PROJECT_CHOOSER, projectChooser );
		stateComposite.put( PROJECT_DETAILS , mainPlaceholder );
		stateComposite.put( PROJECT_CREATE_NEW, projectCreateNew );
	}

	/**
	 * Adds the presenters and adds them as observers to global events.
	 */
	private void addPresenters( ) {
		// Retrieve a project data access object
		CommonDAO<Project, Project, ProjectBuilder> projectDAO = DAOFactory.getDAOFactory().getProjectDAO();
		
		// Create the different presenters and register them with the global events dispatcher.
		ProjectChooserPresenter projectChooserPresenter = new ProjectChooserPresenter( projectChooser, projectDAO );
		GlobalEvents.observe().addObserver( projectChooserPresenter );
		
		CreateNewPresenter createNewPresenter = new CreateNewPresenter( projectCreateNew, projectDAO );
		GlobalEvents.observe().addObserver( createNewPresenter );
		
		MenuPresenter menuPrestenter = new MenuPresenter( menuBar );
		States.observe().addObserver( menuPrestenter );
	}

	/* (non-Javadoc)
	 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
	 */
	/**
	 * Retrieves updates from the state machine. 
	 * Displays and hides views depending on the state.
	 * @param obs The observable instance that sent the message.S
	 * @param obj The list of states (oldState and newState) that is retrieved from the statemachine.
	 */
	//TODO: Move this functionality into the presenter package
	public void update( Observable obs, Object obj ) {
		if( obs.equals( States.observe() ) && obj instanceof Transition ) {
			// This is an transition
			Transition trans = (Transition) obj;
			
			// Hide the old view and show the new
			if( stateComposite.containsKey( trans.dst ) ) {
				stateComposite.get( trans.src ).setVisible( false );
				stateComposite.get( trans.dst ).setVisible( true );
				stackLayout.topControl = stateComposite.get( trans.dst );
			}
		}
	}

	/**
	 * This is the programs main entry point
	 * @param args
	 */
	public static void main( String[] args ) {
		Display display = new Display();
		Shell shell = new Shell( display );
		
		new ScrumPPM( shell );
		
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}
}
